package co.fitstart.weapp.api.web.controller.course;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.demo2do.core.entity.exception.BusinessException;
import com.demo2do.core.entity.result.HttpResult;
import com.demo2do.core.utils.DateFormatUtils;
import com.demo2do.core.utils.DateUtils;
import co.fitstart.entity.course.round.CourseRound;
import co.fitstart.entity.course.schedule.CourseSchedule;
import co.fitstart.entity.principal.Principal;
import co.fitstart.entity.site.Site;
import co.fitstart.entity.user.Student;
import co.fitstart.entity.user.User;
import co.fitstart.weapp.api.entity.Appointment;
import co.fitstart.weapp.api.service.CoachService;
import co.fitstart.weapp.api.service.CourseAppointService;
import co.fitstart.weapp.api.service.CourseRoundService;
import co.fitstart.weapp.api.service.CourseScheduleService;
import co.fitstart.weapp.api.service.SiteService;
import co.fitstart.weapp.api.service.UserService;

/**
 * 约课
 * @author haiyan_xiao
 *
 */
@RestController
@RequestMapping("/profile/courses/{roundId}")
public class CourseAppointController {

    private static final Logger logger = LoggerFactory.getLogger(CourseAppointController.class);

    @Autowired
    private UserService userService;

    @Autowired
    private CourseRoundService courseRoundService;

    @Autowired
    private CourseScheduleService courseScheduleService;

    @Autowired
    private CourseAppointService courseAppointService;

    @Autowired
    private SiteService siteService;

    @Autowired
    private CoachService coachService;

    /**
     * 
     * @param unionid
     * @param courseRoundId
     * @return
     */
    @RequestMapping(value = "/available-days", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE, params = "unionid")
    public HttpResult listAvailableDay(@RequestParam("unionid") String unionid,
                                       @PathVariable("roundId") Long courseRoundId) {
        HttpResult httpResult = new HttpResult();
        
        try {
            User user = userService.load(unionid);
            Student student = userService.getStudent(user);
            CourseRound courseRound = courseRoundService.load(courseRoundId);
            
            courseAppointService.validate(student, courseRound);
            
            List<String> availableDays = courseAppointService.listAvailableDay(courseRound);
            
            httpResult.success().message("获取数据成功")
                                .data("availableDays", availableDays);
        } catch (BusinessException e) {
            httpResult.fail("1").message(e.getMessage());
        } catch (Exception e) {
            logger.error("listAvailableDay() error", e);
            httpResult.fail("500").message("加载数据失败");
        }
        
        return httpResult;
    }

    /**
     * 
     * @param unionid
     * @param courseRoundId
     * @return
     */
    @RequestMapping(value = "/available-sites", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE, params = "unionid")
    public HttpResult listAvailableSite(@RequestParam("unionid") String unionid,
                                        @PathVariable("roundId") Long courseRoundId) {
        HttpResult httpResult = new HttpResult();
        
        try {
            User user = userService.load(unionid);
            Student student = userService.getStudent(user);
            CourseRound courseRound = courseRoundService.load(courseRoundId);
            
            courseAppointService.validate(student, courseRound);
            
            Site site = courseAppointService.getDefaultSite(courseRound, null);
            Map<String, Map<String, List<Site>>> availableSites = new HashMap<>();
            
            if(courseRound.getCourseType().isYear()) {
                Map<String, List<Site>> map = new HashMap<>();
                
                map.put(site.getDistrict(), Arrays.asList(new Site[]{site}));
                availableSites.put(site.getCity(), map);
            } else {
                availableSites = courseAppointService.listAvailableSite(courseRound.getSite());
            }
            
            httpResult.success().message("获取数据成功")
                                .data("site", site)
                                .data("availableSites", availableSites);
        } catch (BusinessException e) {
            httpResult.fail("1").message(e.getMessage());
        } catch (Exception e) {
            logger.error("listAvailableSite() error", e);
            httpResult.fail("500").message("加载数据失败");
        }
        
        return httpResult;
    }

    /**
     * 
     * @param unionid
     * @param courseRoundId
     * @param day
     * @param siteId
     * @param scheduleId
     * @return
     */
    @RequestMapping(value = "/available-times", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE, params = "unionid")
    public HttpResult listAvailableTime(@RequestParam("unionid") String unionid,
                                        @PathVariable("roundId") Long courseRoundId,
                                        @RequestParam(value = "day", required = false) @DateTimeFormat(pattern= "yyyy-MM-dd") Date day,
                                        @RequestParam(value = "siteId", required = false) Long siteId,
                                        @RequestParam(value = "scheduleId", required = false) Long scheduleId) {
        HttpResult httpResult = new HttpResult();
        
        try {
            User user = userService.load(unionid);
            Student student = userService.getStudent(user);
            CourseRound courseRound = courseRoundService.load(courseRoundId);
            CourseSchedule courseSchedule = scheduleId == null ? null : courseScheduleService.load(scheduleId);
            day = day == null ? DateUtils.parseDate(DateFormatUtils.format(new Date(), "yyyy-MM-dd"), "yyyy-MM-dd") : day;
            Site site = courseAppointService.getDefaultSite(courseRound, siteId == null ? null : siteService.load(siteId));
            
            courseAppointService.validate(student, courseRound, courseSchedule, day);
            
            List<Map<String, Object>> remainList = new ArrayList<>();
            if(courseSchedule == null) {
                remainList = courseAppointService.listRemain(courseRound, day, site);
            } else {
                remainList = courseAppointService.listRemain(courseRound, day, site, courseSchedule);
            }
            
            httpResult.success().message("获取数据成功")
                                .data("day", DateFormatUtils.format(day, "yyyy-MM-dd"))
                                .data("site", site)
                                .data("remainList", remainList);
        } catch (BusinessException e) {
            httpResult.fail("1").message(e.getMessage());
        } catch (Exception e) {
            logger.error("listAvailableTime() error", e);
            httpResult.fail("500").message("加载数据失败");
        }
        
        return httpResult;
    }

    /**
     * 
     * @param unionid
     * @param courseRoundId
     * @param siiteId
     * @param occurDate
     * @param occurHour
     * @param scheduleId
     * @return
     */
    @RequestMapping(value = "/coaches", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE, params = "unionid")
    public HttpResult listCoach(@RequestParam("unionid") String unionid,
                                @PathVariable("roundId") Long courseRoundId,
                                @RequestParam("siteId") Long siteId,
                                @RequestParam("occurDate") @DateTimeFormat(pattern= "yyyy-MM-dd") Date occurDate,
                                @RequestParam("occurHour") String occurHour,
                                @RequestParam(value = "scheduleId", required = false) Long scheduleId) {
        HttpResult httpResult = new HttpResult();
        
        try {
            User user = userService.load(unionid);
            Student student = userService.getStudent(user);
            CourseRound courseRound = courseRoundService.load(courseRoundId);
            CourseSchedule courseSchedule = scheduleId == null ? null : courseScheduleService.load(scheduleId);
            Site site = siteService.load(siteId);
            
            courseAppointService.validate(student, courseRound, courseSchedule, site, occurDate, occurHour);
            
            Map<String, Object> coaches = new HashMap<>();
            if(courseSchedule == null) {
                coaches = courseAppointService.listCoach(courseRound, site, occurDate, occurHour);
            } else {
                coaches = courseAppointService.listCoach(courseRound, site, occurDate, occurHour, courseSchedule);
            }
            
            httpResult.success().message("获取数据成功")
                                .data("siteName", site.getName())
                                .data("coaches", coaches)
                                .data("roomLimit", site.getRoomLimit() == null ? 0 : site.getRoomLimit().getRoomLimit())
                                .data("commonLimit", site.getRoomLimit() == null ? 0 : site.getRoomLimit().getCommonLimit());
        } catch (BusinessException e) {
            httpResult.fail("1").message(e.getMessage());
        } catch (Exception e) {
            logger.error("listCoach() error", e);
            httpResult.fail("500").message("加载数据失败");
        }
        
        return httpResult;
    }

    /**
     * 
     * @param unionid
     * @param courseRoundId
     * @param day
     * @param siteId
     * @param coachId
     * @param scheduleId
     * @return
     */
    @RequestMapping(value = "/available-times-by-coach", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE, params = "unionid")
    public HttpResult listAvailableTimeByCoach(@RequestParam("unionid") String unionid,
                                               @PathVariable("roundId") Long courseRoundId,
                                               @RequestParam(value = "day", required = false) @DateTimeFormat(pattern= "yyyy-MM-dd") Date day,
                                               @RequestParam("siteId") Long siteId,
                                               @RequestParam("coachId") Long coachId,
                                               @RequestParam(value = "scheduleId", required = false) Long scheduleId) {
        HttpResult httpResult = new HttpResult();
        
        try {
            User user = userService.load(unionid);
            Student student = userService.getStudent(user);
            CourseRound courseRound = courseRoundService.load(courseRoundId);
            if(day == null) {
                day = DateUtils.parseDate(DateFormatUtils.format(new Date(), "yyyy-MM-dd"), "yyyy-MM-dd");
            }
            CourseSchedule courseSchedule = scheduleId == null ? null : courseScheduleService.load(scheduleId);
            Site site = siteService.load(siteId);
            Principal coach = coachService.load(coachId);
            
            courseAppointService.validate(student, courseRound, courseSchedule, day);
            
            List<Map<String, Object>> remainList = new ArrayList<>();
            if(courseSchedule == null) {
                remainList = courseAppointService.listRemainByCoach(courseRound, site, day, coach);
            } else {
                remainList = courseAppointService.listRemainByCoach(courseRound, site, day, coach, courseSchedule);
            }
            
            httpResult.success().message("获取数据成功")
                                .data("day", DateFormatUtils.format(day, "yyyy-MM-dd"))
                                .data("siteName", site.getName())
                                .data("coachName", coach.getName())
                                .data("remainList", remainList)
                                .data("roomLimit", site.getRoomLimit() == null ? 0 : site.getRoomLimit().getRoomLimit())
                                .data("commonLimit", site.getRoomLimit() == null ? 0 : site.getRoomLimit().getCommonLimit())
                                .data("give", courseRound.getCourse().isGive());
        } catch (BusinessException e) {
            httpResult.fail("1").message(e.getMessage());
        } catch (Exception e) {
            logger.error("listAvailableTimeByCoach() error", e);
            httpResult.fail("500").message("加载数据失败");
        }
        
        return httpResult;
    }

    /**
     * 
     * @param unionid
     * @param courseRoundId
     * @param siteId
     * @param coachId
     * @param occurDate
     * @param occurHour
     * @param roomType
     * @param scheduleId
     * @return
     */
    @RequestMapping(value = "/appoint", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE, params = "unionid")
    public HttpResult appoint(@RequestParam("unionid") String unionid,
                              @PathVariable("roundId") Long courseRoundId,
                              @RequestBody Appointment appointment,
                              @RequestParam(value = "scheduleId", required = false) Long scheduleId) {
        HttpResult httpResult = new HttpResult();
        
        try {
            if(appointment.isValid()) {
                User user = userService.load(unionid);
                Student student = userService.getStudent(user);
                CourseRound courseRound = courseRoundService.load(courseRoundId);
                Site site = siteService.load(appointment.getSiteId());
                Principal coach = coachService.load(appointment.getCoachId());
                CourseSchedule courseSchedule = scheduleId == null ? null : courseScheduleService.load(scheduleId);
                
                courseAppointService.validate(student, courseRound, courseSchedule, site, appointment.getOccurDate(), appointment.getOccurHour());
                
                if(courseSchedule == null) {
                    if(appointment.getRoomType() == null) {
                        courseAppointService.appointSchedule(courseRound, site, coach, appointment.getOccurDate(), appointment.getOccurHour());
                    } else {
                        courseAppointService.appointSchedule(courseRound, site, coach, appointment.getOccurDate(), appointment.getOccurHour(), appointment.getRoomType());
                    }
                } else {
                    if(appointment.getRoomType() == null) {
                        courseAppointService.changeSchedule(courseRound, site, coach, appointment.getOccurDate(), appointment.getOccurHour(), courseSchedule);
                    } else {
                        courseAppointService.changeSchedule(courseRound, site, coach, appointment.getOccurDate(), appointment.getOccurHour(), appointment.getRoomType(), courseSchedule);
                    }
                }
                
                httpResult.success().message("预约成功");
            } else {
                httpResult.fail("1").message("请求参数有误");
            }
        } catch (BusinessException e) {
            httpResult.fail("1").message(e.getMessage());
        } catch (Exception e) {
            logger.error("listAvailableTimeByCoach() error", e);
            httpResult.fail("500").message("预约失败");
        }
        
        return httpResult;
    }

    @RequestMapping(value = "/schedules/{scheduleId}/cancel", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE, params = "unionid")
    public HttpResult cancel(@RequestParam("unionid") String unionid,
                             @PathVariable("roundId") Long courseRoundId,
                             @PathVariable("scheduleId") Long courseScheduleId) {
        HttpResult httpResult = new HttpResult();
        
        try {
            User user = userService.load(unionid);
            Student student = userService.getStudent(user);
            CourseSchedule courseSchedule = courseScheduleService.load(courseScheduleId);
            
            courseAppointService.validateCancel(student, courseSchedule);
            
            courseAppointService.cancelSchedule(courseSchedule);
            
            httpResult.success().message("取消预约成功");
        } catch (BusinessException e) {
            httpResult.fail("1").message(e.getMessage());
        } catch (Exception e) {
            logger.error("listAvailableTimeByCoach() error", e);
            httpResult.fail("500").message("取消预约失败");
        }
        
        return httpResult;
    }
}
